<template>
  <div
    :class="{
      'node-triangle': card.appearance.type == 'triangle' && !flip,
      'node-triangle-flipped': card.appearance.type == 'triangle' && flip,
      node: card.appearance.type == 'rect',
      'general-node': true,
      'on-select': selected,
    }"
    :style="{ width: width }"
    @dblclick.stop="drawerShow = true"
  >
    <el-popover
      trigger="hover"
      :show-after="500"
      popper-class="ligralpy-popover"
    >
      <el-row class="node-title">
        <p>{{ nodeID }}</p>
      </el-row>
      <p
        :key="param"
        v-for="param in card.params"
        style="
          margin-top: 3px;
          margin-bottom: 3px;
          text-align: start;
          padding-left: 30px;
          font-size: 10px;
        "
      >
        {{ param.name }}: {{ currentParamValue(param.name) }}
      </p>
      <el-tooltip effect="dark" :content="$tr('Delete Node')">
        <el-button @click="deleteNode" type="danger" size="small">
          <el-icon>
            <delete />
          </el-icon>
        </el-button>
      </el-tooltip>
      <el-tooltip effect="dark" :content="$tr('Flip')">
        <el-button @click="flipNode" size="small">
          <el-icon>
            <switch-icon />
          </el-icon>
        </el-button>
      </el-tooltip>

      <el-tooltip effect="dark" :content="$tr('Edit Parameters')">
        <el-button @click="editParams" size="small">
          <el-icon>
            <edit />
          </el-icon>
        </el-button>
      </el-tooltip>

      <template #reference>
        <div
          :class="{
            refblock: true,
            'refblock-for-plain-title': card.appearance.figureMode == 'none',
          }"
          :style="{
            width:
              card.appearance.xScale == null
                ? '80px'
                : card.appearance.xScale * 80 + 'px',
          }"
        >
          <math-block
            v-if="card.appearance.figureMode == 'latex'"
            :expr="this.card.appearance.source"
            :paramValues="paramValues"
          ></math-block>
          <svg-icon
            v-if="card.appearance.figureMode == 'icon'"
            :icon-class="this.card.appearance.source"
            class="icon"
          />
          <!-- <el-tooltip :content="formattedPlainTitle"> -->
          <div v-if="card.appearance.figureMode == 'none'" class="plain-title">
            <p
              style="margin-top: 0px; line-height: 16px"
              v-for="titleRow in formattedPlainTitle"
              :key="titleRow"
            >
              {{ titleRow }}
            </p>
          </div>
          <!-- </el-tooltip> -->
        </div>
      </template>
    </el-popover>

    <el-drawer v-model="drawerShow" :title="$tr('Node Configurations')">
      <span>{{ $tr("Parameter Configurations") }}</span>
      <dynamic-form
        :data="formData"
        @data-changed="onDataChanged"
      ></dynamic-form>
      <p>{{ $tr("Node Descriptions") }}</p>
      <span>{{ card.description }}</span>
      <div style="margin-top: 10px">
        <el-button
          @click="editPorts('output')"
          :disabled="!card.outputVariable"
          size="small"
        >
          {{ $tr("Edit Output Ports") }}
        </el-button>
        <el-button
          @click="editPorts('input')"
          :disabled="!card.inputVariable"
          size="small"
        >
          {{ $tr("Edit Input Ports") }}
        </el-button>
      </div>
    </el-drawer>
    <p class="node-id-annotation">{{ nodeID }}</p>
  </div>
</template>

<script lang="ts">
import { Card, Param } from "./models";
import { defineComponent, reactive } from "@vue/runtime-core";
import { getCardByType } from "@/api/cards";
import { ref, PropType } from "vue";
import { Edit, Delete, Switch } from "@element-plus/icons-vue";
import DynamicForm from "@/components/dynamicform/DynamicForm.vue";
import {
  emitDeleteNode,
  emitEditPortsOnNode,
  emitFlipNode,
  emitLoad,
  emitLoadChartByName,
  emitNodeParamsChanged,
} from "@/components/EventBus";
import { DATA_TYPE, FieldType } from "../dynamicform/formdatastruct";
import MathBlock from "@/components/math/MathBlock.vue";

function sFormat(template: string) {
  return (data: Param[]) => {
    for (const param of data) {
      const paramName = param.name;
      template = template.replaceAll(`$\{${paramName}}`, param.value);
    }
    return template.split("<br>");
    // return template;
  };
}

export default defineComponent({
  components: { DynamicForm, MathBlock, Edit, Delete, SwitchIcon: Switch },
  props: {
    type: {
      type: String,
      required: true,
    },
    nodeID: {
      type: String,
      required: true,
    },
    paramValues: {
      type: Array as PropType<Param[]>,
      required: true,
    },
    flip: {
      type: Boolean,
      required: true,
    },
    selected: {
      type: Boolean,
      required: true,
    },
  },
  setup() {
    const title = ref("标题");
    const card = ref<Card>({
      id: "",
      title: "",
      description: "...",
      category: "internal",
      params: [],
      inputs: [],
      outputs: [],
      appearance: {
        type: "rect",
        figureMode: "none",
        source: "",
      },
      inputVariable: false,
      outputVariable: false,
    });
    const drawerShow = ref(false);
    const formData: Record<string, FieldType> = reactive({});
    const infoVisible = ref(false);
    return {
      title,
      card,
      drawerShow,
      formData,
      infoVisible,
    };
  },
  methods: {
    async load() {
      this.card = await getCardByType(this.type);
      if (
        this.card.appearance.figureMode == "none" &&
        this.card.appearance.source != ""
      ) {
        this.title = this.card.appearance.source;
      } else {
        this.title = this.card.title;
      }
      for (const i in this.card.params) {
        const paramScheme = this.card.params[i];
        let type: DATA_TYPE.string | DATA_TYPE.signal = DATA_TYPE.string;
        if (paramScheme.type == "signal") {
          type = DATA_TYPE.signal;
        } else if (paramScheme.type == "string") {
          type = DATA_TYPE.string;
        } else {
          // TODO 补充这里的类型
          throw Error(`Unrecognized parameter type ${paramScheme.type}`);
        }
        const param = this.paramValues.find(
          (p: Param) => p.name == paramScheme.name
        );

        let paramValue: any = null;
        if (param == null) {
          console.warn(`Param ${paramScheme.name}  is not filled yet.`);
        } else {
          paramValue = param.value;
        }
        this.formData[paramScheme.name] = {
          Type: type,
          Default: null,
          Required: paramScheme.required,
          Value: paramValue,
        } as FieldType;
      }
    },
    onDataChanged(data: Record<string, string | number>) {
      emitNodeParamsChanged(this.nodeID, data);
    },
    flipNode() {
      emitFlipNode(this.nodeID);
    },
    deleteNode() {
      emitDeleteNode(this.nodeID);
    },
    editPorts(direction: "input" | "output") {
      if (
        (this.card.inputVariable && direction == "input") ||
        (this.card.outputVariable && direction == "output")
      ) {
        emitEditPortsOnNode(this.nodeID, direction);
      }
    },
    editParams() {
      if (
        this.card.category == "internal" ||
        this.card.category == "external"
      ) {
        this.drawerShow = true;
      } else if (this.card.category == "custom") {
        emitLoadChartByName(this.card.id);
      } else {
        throw Error("Not implemented card category :" + this.card.category);
      }
    },
  },
  mounted() {
    this.load();
  },
  computed: {
    formattedPlainTitle(): string[] {
      return sFormat(this.title)(this.paramValues);
    },
    currentParamValue() {
      return (name: string) => {
        const pv: Param | undefined = this.paramValues.find(
          (pv: Param) => pv.name == name
        );
        if (pv == null) {
          return "";
        } else {
          return pv.value;
        }
      };
    },
    width(): string {
      if (this.card.appearance.type === "rect") {
        return this.card.appearance.xScale == null
          ? "80px"
          : this.card.appearance.xScale * 80 + "px";
      } else if (this.card.appearance.type == "triangle") {
        return "0px";
      }
      throw Error(
        "Unrecognized card appearance type " + this.card.appearance.type
      );
      // ((card.appearance.type != 'triangle') && (card.appearance.xScale == null)) ? '80px' : card.appearance.xScale * 80 + 'px'
    },
  },
});
</script>

<style scoped>
.general-node {
  text-align: center;
}
.node {
  background-color: var(--block-bg);
  width: 80px;
  height: 90px;
  font-size: 14px;
}

.on-select {
  box-shadow: 5px 5px;
}

.node .refblock {
  height: 90px;
  line-height: 90px;
}

.refblock-for-plain-title {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.refblock .plain-title {
  margin: 0px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  margin-left: 10px;
  margin-right: 10px;
}

.refblock .icon {
  margin-top: 20px;
  font-size: 2.8em;
}

.node-triangle {
  width: 0px;
  height: 0px;
  border-left: 80px solid var(--block-bg);
  border-top: 40px solid transparent;
  border-bottom: 40px solid transparent;
}

.node-triangle .refblock {
  width: 80px;
  height: 80px;
  margin-left: -80px;
  margin-top: -40px;
  line-height: 80px;
}

.node-triangle-flipped {
  width: 0px;
  height: 0px;
  border-right: 80px solid var(--block-bg);
  border-top: 40px solid transparent;
  border-bottom: 40px solid transparent;
}

.node-triangle-flipped .refblock {
  width: 80px;
  height: 80px;
  /* margin-left: 90px; */
  margin-top: -40px;
  line-height: 80px;
}

.node-title {
  justify-content: center;
  align-items: center;
  font-size: 14px;
  line-height: 14px;
  color: #ffffff;
  background: var(--primary);
  height: 16px;
}

.node-title p {
  margin-left: 5px;
  margin-top: 2px;
  margin-bottom: 2px;
}

.node-id-annotation {
  font-size: 0.8em;
  line-height: 12px;
  margin: 2px;
}

.node-triangle .node-id-annotation {
  margin-left: -80px;
}
</style>

<style>
.node-title .el-button {
  width: 16px;
  height: 16px;
  padding: 8px;
  margin-left: 5px;
}

.ligralpy-popover {
  background-color: var(--bg) !important;
}
</style>
